<template>
	<div class="home_index">
		<p class="home_name">✨ 买单小助手 ✨</p>
		<div class="home_btn">
			<p class="home_title">参与小伙伴数量:</p>
			<el-input
				v-model="input"
				placeholder="参与小伙伴数量"
				class="home_input"
			/>
			<el-button type="primary" class="home_sure" @click="setNumber"
				>确定</el-button
			>
			<el-button class="home_reset" @click="setReset">重置</el-button>
		</div>
		<p class="hoem_prompt" v-if="winning">
			🎉🎉恭喜选择
			<span class="home_nmb">{{ winning }}</span> 号的小伙伴中奖🎉🎉
		</p>
		<p class="hoem_prompt" v-else>暂时没有人中奖哦</p>
		<canvas
			id="mycanvas"
			ref="mycanvas"
			:width="cnWidth"
			:height="cnHeight"
			@click="clickCanvasFun"
		></canvas>
		<div class="home_detail">
			<p class="home_one">玩法说明：</p>
			<p class="home_two">
				1.确定参与游戏的小伙伴数量之后，小伙伴每人选一个喜欢的号码。
			</p>
			<p class="home_two">
				2.点击对应的号码之后会开始抽奖动画，抽奖结果会在上面提示。
			</p>
			<p class="home_two">
				3.如果倒数第二个小伙伴抽完之后依旧没有人中奖，则默认最后一个小伙伴中奖哦!
			</p>
		</div>
	</div>
</template>
<script setup lang="ts">
import { ElMessage } from "element-plus";
import { onMounted, ref, toRefs } from "vue";
interface LineCoordStyle {
	oneX: number;
	oneY: number;
}
interface ArrType {
	oneX: number;
	oneY: number;
	oneR: number;
	type: string;
	lineCoord: LineCoordStyle;
}
interface CoordArrType {
	oneX: number;
	oneY: number;
}
interface OneLineType {
	left: boolean;
	right: boolean;
	bottom: boolean;
	index: number;
	coordArr: CoordArrType[];
}
interface CoordOneType {
	coordTop: ArrType;
	coordBot: ArrType;
	coordLine: OneLineType;
}
type CoordALl = CoordOneType[];

const mycanvas = ref(null);
let context = ref<any>(null);
let personNmb = ref(4); // 设置初始人数
let coordAll = ref<CoordALl>([]); // 存储所有坐标数据
let cnWidth = ref(0); // canvas初始宽
let cnHeight = ref(0); // canvas初始高
let twistNumb = ref(4); // 转折点数
let input = ref(""); // 参与人数
let winning = ref(0); // 中奖号码
/**
 * @function 设置参与人数
 */
const setNumber = () => {
	let numb = Number(input.value);
	if (numb < 2) {
		ElMessage({
			message: "最少需要两位小伙伴参与哦!",
			type: "warning",
		});
		return;
	} else if (numb > 10) {
		ElMessage({
			message: "最多只能十位小伙伴参与哦!",
			type: "warning",
		});
		return;
	}
	twistNumb.value = numb;
	personNmb.value = numb;
	context.value.clearRect(0, 0, cnWidth.value, cnHeight.value);
	getPerson();
	drawFun(coordAll.value);
};
/**
 * @function 重置绘图
 */
const setReset = () => {
	isClick.value = true;
	clickArr.value = [];
	context.value.clearRect(0, 0, cnWidth.value, cnHeight.value);
	drawFun(coordAll.value);
};
/**
 * @function 生成随机数
 * @param max 随机值上限
 * @param min 随机值下限
 * @returns 随机数
 */
const randerNumFun = (max: number, min: number) => {
	return Math.floor(Math.random() * (max - min)) + min;
};

/**
 * @function 动态设置canvas宽高
 */
const setStyle = () => {
	let widthAll = document.documentElement.clientWidth;
	let heightAll = document.documentElement.clientHeight;
	cnWidth.value = widthAll * 0.8;
	cnHeight.value = heightAll * 0.6;
	getPerson(); // 生成坐标
};

/**
 * @function 生成需要的坐标数组
 * @description 生成的每个坐标包括coordTop:头部坐标 coordBot:底部坐标 coordLine:转折点做成的数组
 */
const getPerson = () => {
	coordAll.value = [];
	let interval = cnWidth.value / personNmb.value; // 获取每个人对应格子宽度
	let oneTopX = interval / 2; // 获取格子中间位置=》顶部第一个人员所在的x轴坐标
	let oneTopY = 50; // 设置顶部人员的y轴坐标
	let oneTopR = 30; // 设置顶部人员圆圈半径
	let oneBotY = cnHeight.value - oneTopY; // 设置底部结果的y轴坐标
	let i = personNmb.value;
	let itemOne = oneTopX;
	while (i > 0) {
		// 顶部坐标
		let oneObj = {
			oneX: itemOne,
			oneY: oneTopY,
			oneR: oneTopR,
			type: "top",
			lineCoord: {
				oneX: itemOne, // 连接线的起点x轴坐标
				oneY: oneTopY + oneTopR, // 连接线y轴坐标
			},
		};
		// 底部坐标
		let oneObjbot = {
			oneX: itemOne,
			oneY: oneBotY,
			oneR: oneTopR,
			type: "bot",
			lineCoord: {
				oneX: itemOne, // 连接线的终点x轴坐标
				oneY: oneBotY - oneTopR, // 连接线的终点y轴坐标
			},
		};
		// 生成转折坐标点
		let lineArr = makeTwistFun(
			itemOne,
			oneTopY + oneTopR,
			oneBotY - oneTopR,
			personNmb.value - i,
			twistNumb.value
		);
		itemOne = itemOne + interval;
		let obj = {
			coordTop: oneObj,
			coordBot: oneObjbot,
			coordLine: lineArr,
		};
		coordAll.value.push(obj);
		i--;
	}
};
/**
 * @function 转折坐标点生成
 * @param x x轴坐标
 * @param yt y轴起点坐标
 * @param yb y轴终点坐标
 * @param index 第几条线
 * @param numb 生成几个点
 * @returns oneLine 返回处理之后的坐标点组成的数组
 */
const makeTwistFun = (
	x: number,
	yt: number,
	yb: number,
	index: number,
	numb: number
) => {
	let oneLine: OneLineType = {
		left: true,
		right: true,
		bottom: true,
		index: 0,
		coordArr: [],
	};
	if (index == 0) {
		// 开始的线
		oneLine.left = false;
	} else if (index == personNmb.value - 1) {
		// 结束的线
		oneLine.right = false;
	}
	oneLine.index = index;
	oneLine.coordArr = randerAllFun(x, yt, yb, numb);
	return oneLine;
};

/**
 * @function 生成连接线上的随机点
 * @param x x轴坐标
 * @param yt y轴起点坐标
 * @param yb y轴终点坐标
 * @param numb 生成几个点
 * @returns coordArr 返回坐标点组成的数组
 */
const randerAllFun = (x: number, yt: number, yb: number, numb: number) => {
	let i = numb;
	let arr: number[] = [];
	while (i > 0) {
		let num = randerNumFun(yb - 20, yt + 20);
		if (arr.indexOf(num) == -1) {
			// 随机数边界处理
			arr.push(num);
			i--;
		}
	}
	let newArr = arr.sort();
	let coordArr: CoordArrType[] = [];
	newArr.forEach((item) => {
		let obj = {
			oneX: 0,
			oneY: 0,
		};
		obj.oneX = x;
		obj.oneY = item;
		coordArr.push(obj);
	});
	return coordArr;
};
setStyle();
let resultArr = ref<number[]>([]); // 结果数组
/**
 * @function 绘制基础的图形
 * @param coordAll 总体坐标对象
 */
const drawFun = (coordAll: CoordALl) => {
	let length = coordAll.length;
	resultArr.value = makeNum();
	for (let i = 0; i < length; i++) {
		drawBasis(coordAll[i].coordTop, i, resultArr.value);
		drawBasis(coordAll[i].coordBot, i, resultArr.value);
		drawLine(
			coordAll[i].coordTop.lineCoord.oneX,
			coordAll[i].coordTop.lineCoord.oneY,
			coordAll[i].coordBot.lineCoord.oneX,
			coordAll[i].coordBot.lineCoord.oneY
		);
	}
};
/**
 * @function 绘制连接线
 * @param xTop 线开始的x轴坐标
 * @param yTop 线开始的y轴坐标
 * @param xBot 线结束的x轴坐标
 * @param YBot 线结束的y轴坐标
 */
const drawLine = (xTop: number, yTop: number, xBot: number, YBot: number) => {
	context.value.strokeStyle = "white"; // 线的颜色
	context.value.lineWidth = 8; // 线的宽度
	context.value.beginPath(); // 开始绘制
	context.value.moveTo(xTop, yTop); // 绘制起点
	context.value.lineTo(xBot, YBot); // 绘制终点
	context.value.stroke(); // 描边
	context.value.closePath(); // 结束绘制
};
/**
 * @function 绘制圆形
 * @param value 圆心坐标
 * @param index 第几个
 * @param arr 随机状态数组 用于设置中奖
 */
const drawBasis = (value: ArrType, index: number, arr: number[]) => {
	context.value.beginPath(); // 开始绘制
	context.value.lineWidth = 4; // 线的宽度
	context.value.arc(value.oneX, value.oneY, value.oneR, 0, 2 * Math.PI); // x, y, 半径, 起始弧度, 结束弧度, 顺时针or逆时针
	context.value.strokeStyle = "white";
	context.value.stroke(); // 描边
	context.value.closePath(); // 结束绘制
	// 绘制字体
	context.value.beginPath(); // 开始绘制
	context.value.textAlign = "center"; // 左右对齐方式，相对于指定圆点
	context.value.textBaseline = "middle"; // 上下对齐方式，相对于指定圆点
	context.value.font = '20px "微软雅黑"'; // 设置字体大小以及字体种类

	if (value.type == "top") {
		context.value.fillStyle = "white"; // 设置填充字体颜色
		context.value.fillText(`${index + 1}号`, value.oneX, value.oneY); // 设置填充字体内容以及坐标
	} else {
		if (arr[index]) {
			context.value.fillStyle = "red"; // 设置填充字体颜色
			context.value.fillText(`中奖`, value.oneX, value.oneY); // 设置填充字体内容以及坐标
		} else {
			context.value.fillStyle = "white"; // 设置填充字体颜色
			context.value.fillText(`谢谢`, value.oneX, value.oneY); // 设置填充字体内容以及坐标
		}
	}
	// context.value.strokeStyle = "RGB(255, 0, 0)"; // 设置描边颜色
	// context.value.strokeText(内容, x, y, MaxLength); // 描边字体
	context.value.closePath(); // 结束绘制
};
/**
 * @function 生成状态数组
 * @returns arr 返回由一个1和n个0组成的状态数组
 */
const makeNum = () => {
	let arr = new Array(personNmb.value).fill(0);
	let num = randerNumFun(personNmb.value, 0);
	arr[num] = 1;
	return arr;
};
let startCoordX = ref(0); // 开始x轴坐标
let startCoordY = ref(0); // 开始y轴坐标
let endCoordX = ref(0); // 结束x轴坐标
let endCoordY = ref(0); // 结束y轴坐标
let clickItem = ref<any>(null); // 存储点击
let time = ref<any>(null); // 存储动画执行函数
let phase = ref(0); // 记录转折次数
let direction = ref("bot"); // 记录方向
let isClick = ref(true); // 点击事件截流
let clickArr = ref<number[]>([]); // 存储已经点击过的
let noeClick = ref(0); // 当前点击
/**
 * @function 绑定点击事件
 * @param e 鼠标点击信息
 */
const clickCanvasFun = (e: MouseEvent) => {
	winning.value = 0;
	if (isClick.value) {
		isClick.value = false;
		let length = coordAll.value.length;
		for (let i = 0; i < length; i++) {
			let isMe = isMeFun(coordAll.value[i].coordTop, e);
			if (isMe) {
				if (clickArr.value.indexOf(i) == -1) {
					noeClick.value = i;
					context.value.clearRect(0, 0, cnWidth.value, cnHeight.value);
					drawFun(coordAll.value);
					cartoonFun(coordAll.value[i]);
					clickArr.value.push(i);
				} else {
					ElMessage({
						message: "这个小伙伴已经抽过奖喽!",
						type: "warning",
					});
					isClick.value = true;
				}
			} else {
				isClick.value = true;
			}
		}
	}
};
/**
 * @function 判断点击是否在指定图形内部
 * @param item 指定图形中心
 * @param e 鼠标点击信息
 * @returns 是否在图形内部 true:在,false:不在
 */
const isMeFun = (item: ArrType, e: MouseEvent) => {
	const { offsetX, offsetY } = e; // 获取点击位置在画布的位置
	const { oneX, oneY, oneR } = toRefs(item); // 获取圆心
	const a = offsetX - oneX.value;
	const b = offsetY - oneY.value;
	const c = Math.sqrt(a * a + b * b);
	return oneR.value > c ? true : false;
};
/**
 * @function 绘制动画线
 * @param item 点击的直线数据
 */
const cartoonFun = (item: CoordOneType) => {
	clickItem.value = item;
	phase.value = 0;
	startCoordX.value = item.coordTop.lineCoord.oneX;
	startCoordY.value = item.coordTop.lineCoord.oneY;
	endCoordX.value = item.coordLine.coordArr[phase.value].oneX;
	endCoordY.value = item.coordLine.coordArr[phase.value].oneY;
	countSpacing(); // 获取移动间距
	subsectionFun();
};
let x = ref(0); // 记录x轴变化间隔
let y = ref(0); // 记录y轴变化间隔
let startY = ref(0); // 复制起点位置，用于判断上下位置
/**
 * @function 动画边界判断函数
 */
const isGoOnFun = () => {
	if (direction.value == "left") {
		if (startY.value >= endCoordY.value) {
			// 在目标点上面
			if (
				startCoordX.value <= endCoordX.value &&
				startCoordY.value <= endCoordY.value
			) {
				return true;
			} else {
				return false;
			}
		} else {
			// 在目标点下面
			if (
				startCoordX.value <= endCoordX.value &&
				startCoordY.value >= endCoordY.value
			) {
				return true;
			} else {
				return false;
			}
		}
	} else if (direction.value == "right") {
		if (startY.value >= endCoordY.value) {
			// 在目标点上面
			if (
				startCoordX.value >= endCoordX.value &&
				startCoordY.value <= endCoordY.value
			) {
				return true;
			} else {
				return false;
			}
		} else {
			// 在目标点下面
			if (
				startCoordX.value >= endCoordX.value &&
				startCoordY.value >= endCoordY.value
			) {
				return true;
			} else {
				return false;
			}
		}
	} else if (direction.value == "bot") {
		if (startCoordY.value >= endCoordY.value) {
			return true;
		} else {
			return false;
		}
	}
};
/**
 * @function 动画循环执行函数
 */
const subsectionFun = () => {
	if (isGoOnFun()) {
		startY.value = JSON.parse(JSON.stringify(startCoordY.value));
		time.value = null;
		phase.value = phase.value + 1;
		if (phase.value == twistNumb.value) {
			direction.value = "bot";
			endCoordX.value = clickItem.value.coordBot.lineCoord.oneX;
			endCoordY.value = clickItem.value.coordBot.lineCoord.oneY;
			countSpacing();
			subsectionFun();
			return;
		} else if (phase.value > twistNumb.value) {
			isClick.value = true;
			if (resultArr.value[clickItem.value.coordLine.index]) {
				winning.value = noeClick.value + 1;
				ElMessage({
					message: `🎉 恭喜选择${noeClick.value + 1}号的小伙伴中奖`,
					type: "success",
				});
				setReset(); // 重置
			} else {
				if (clickArr.value.length + 1 == personNmb.value) {
					let i = personNmb.value - 1;
					while (i > 0) {
						if (clickArr.value.indexOf(i) == -1) {
							winning.value = i + 1;
							ElMessage({
								message: `🎉 恭喜选择${i + 1}号的小伙伴中奖`,
								type: "success",
							});
							setReset(); // 重置
							return;
						} else {
							i--;
						}
					}
				} else {
					ElMessage(`🥁下次继续`);
				}
			}
			return;
		}
		let rendNum = randerNumFun(3, 0);
		switch (rendNum) {
			case 0: // left
				if (clickItem.value.coordLine.left) {
					direction.value = "left";
					clickItem.value = coordAll.value[clickItem.value.coordLine.index - 1];
					endCoordX.value =
						clickItem.value.coordLine.coordArr[phase.value].oneX;
					endCoordY.value =
						clickItem.value.coordLine.coordArr[phase.value].oneY;
				} else {
					direction.value = "right";
					clickItem.value = coordAll.value[clickItem.value.coordLine.index + 1];
					endCoordX.value =
						clickItem.value.coordLine.coordArr[phase.value].oneX;
					endCoordY.value =
						clickItem.value.coordLine.coordArr[phase.value].oneY;
				}
				countSpacing();
				subsectionFun();
				break;
			case 1: // bot
				direction.value = "bot";
				endCoordX.value = clickItem.value.coordBot.lineCoord.oneX;
				endCoordY.value = clickItem.value.coordBot.lineCoord.oneY;
				countSpacing();
				subsectionFun();
				break;
			case 2: // right
				if (clickItem.value.coordLine.right) {
					direction.value = "right";
					clickItem.value = coordAll.value[clickItem.value.coordLine.index + 1];
					endCoordX.value =
						clickItem.value.coordLine.coordArr[phase.value].oneX;
					endCoordY.value =
						clickItem.value.coordLine.coordArr[phase.value].oneY;
				} else {
					direction.value = "left";
					clickItem.value = coordAll.value[clickItem.value.coordLine.index - 1];
					endCoordX.value =
						clickItem.value.coordLine.coordArr[phase.value].oneX;
					endCoordY.value =
						clickItem.value.coordLine.coordArr[phase.value].oneY;
				}
				countSpacing();
				subsectionFun();
				break;
			default:
				break;
		}
		return;
	} else {
		let endX = startCoordX.value + x.value;
		let endY = startCoordY.value + y.value;
		cartLineFun(startCoordX.value, startCoordY.value, endX, endY);
		time.value = requestAnimationFrame(subsectionFun);
	}
};
/**
 * @function 计算间隔
 */
const countSpacing = () => {
	x.value = (endCoordX.value - startCoordX.value) / 50;
	y.value = (endCoordY.value - startCoordY.value) / 50;
};
/**
 * @function 动画线配置
 * @param startX 起点x轴坐标
 * @param startY 起点y轴坐标
 * @param endX 终点x轴坐标
 * @param endY 终点y轴坐标
 */
const cartLineFun = (
	startX: number,
	startY: number,
	endX: number,
	endY: number
) => {
	context.value.strokeStyle = "pink"; // 线的颜色
	context.value.lineWidth = 4; // 线的宽度
	context.value.beginPath(); // 开始绘制
	context.value.moveTo(startX, startY); // 绘制起点
	context.value.lineTo(endX, endY); // 绘制终点
	context.value.stroke(); // 描边
	context.value.closePath(); // 结束绘制
	startCoordX.value = endX; // 重置起点
	startCoordY.value = endY; // 重置起点
};
onMounted(() => {
	const c: any = mycanvas.value;
	context.value = c.getContext("2d");
	drawFun(coordAll.value);
});
</script>
<style lang="less" scoped>
.home_index {
	width: 100vw;
	height: 100vh;
	background-image: url("./../../../assets/image/1177.png_300.png");
	background-size: 100% 100%;
	position: relative;
	text-align: center;
	.home_name {
		height: 70px;
		line-height: 70px;
		font-size: 24px;
		color: white;
	}
	.home_btn {
		display: flex;
		justify-content: center;
		align-items: center;
		.home_title {
			color: white;
		}
	}

	.home_input {
		width: 20%;
		margin: 0 20px 0 30px;
	}
	.home_sure {
		width: 100px;
	}
	.home_reset {
		width: 100px;
	}

	.hoem_prompt {
		margin-top: 20px;
		font-size: 22px;
		color: #45f896;
		text-shadow: 0px 12px 17px rgba(202, 235, 18, 0.76);
		.home_nmb {
			color: red;
		}
	}

	#mycanvas {
		margin-top: 20px;
	}
	.home_detail {
		width: 600px;
		text-align: left;
		margin: 0 auto;
		.home_one {
			margin-top: 20px;
			color: white;
		}
		.home_two {
			font-size: 16px;
			font-family: Microsoft YaHei;
			font-weight: 400;
			color: white;
		}
	}
}
</style>
